package com.jackrain.nea.core.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.TypeUtils;
import com.jackrain.nea.core.api.AdColumnSaveCmd;
import com.jackrain.nea.core.db.Tools;
import com.jackrain.nea.core.mapper.AdColumnMapper;
import com.jackrain.nea.core.mapper.AdTableMapper;
import com.jackrain.nea.core.mapper.AdTableSqlMapper;
import com.jackrain.nea.core.mapper.MapperShortcut;
import com.jackrain.nea.core.utility.CommandData;
import com.jackrain.nea.exception.NDSException;
import com.jackrain.nea.sys.CommandAdapter;
import com.jackrain.nea.util.ValueHolder;
import com.jackrain.nea.web.face.User;
import com.jackrain.nea.web.query.QuerySession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.function.Function;

@Slf4j
@Component
@Service(protocol = "dubbo", validation = "true", version = "1.0", group = "ad")
public class AdColumnSaveCmdImpl extends CommandAdapter implements AdColumnSaveCmd {

    @Autowired
    private MapperShortcut mapperShortcut;
    @Autowired
    private AdColumnMapper adColumnMapper;
    @Autowired
    private AdTableMapper adTableMapper;
    @Autowired
    private AdTableSqlMapper adTableSqlMapper;

    @Override
    @Transactional
    public ValueHolder execute(QuerySession session) throws NDSException {
        CommandData data = new CommandData(session);

        Long objectId = null, AD_LIMITVALUE_GROUP_ID = null, REF_COLUMN_ID = null, ORDERNO = null;
        String coltype = null, dbname = null, desc = null, displaytype = null, interpreter = null, summethod = null,
                SEQUENCENAME = null, v_mask = null, isak = null, isdk = null, v_MODIFIABLE = null, v_null = null,
                v_obtainmanner = null;
        JSONObject model = data.getMainData("AD_COLUMN", true);
        String tabname = null;
        String v_fkdisplay = null;

        //获取参数
        coltype = model.getString("COLTYPE");
        dbname = model.getString("DBNAME");
        desc = model.getString("DESCRIPTION");
        displaytype = model.getString("DISPLAYTYPE");
        interpreter = model.getString("INTERPRETER");
        summethod = model.getString("SUMMETHOD");
        SEQUENCENAME = model.getString("SEQUENCENAME");
        v_mask = model.getString("MASK");
        isak = model.getString("ISAK");
        isdk = model.getString("ISDK");
        v_MODIFIABLE = model.getString("MODIFIABLE");
        v_null = model.getString("NULLABLE");
        v_obtainmanner = model.getString("OBTAINMANNER");
        v_fkdisplay = model.getString("FKDISPLAY");
        AD_LIMITVALUE_GROUP_ID = model.getLong("AD_LIMITVALUE_GROUP_ID");
        REF_COLUMN_ID = model.getLong("REF_COLUMN_ID");
        ORDERNO = com.jackrain.nea.util.Tools.getLong(model.getLong("ORDERNO"), -1);


        int tableid = -1;
        if (data.isInserting()) {

            if (dbname == null || dbname.length() == 0) {
                return data.error(-1, "字段名", "不能为空");
            }

            objectId = Tools.getSequence("AD_COLUMN");

            isak = isak != null ? isak : "N";
            isdk = isdk != null ? isdk : "N";
            v_MODIFIABLE = v_MODIFIABLE != null ? v_MODIFIABLE : "N";
            v_null = v_null != null ? v_null : "N";

            //set参数
            model.put("ID", objectId);

            data.setInsertDefaultValue(model);
            tableid = model.getInteger("AD_TABLE_ID");
            tabname = adTableMapper.selectNameById(tableid);
            if (adColumnMapper.exists(tableid, dbname)) {
                return data.error(-1, "字段名", "已经存在");
            }
        } else if (data.isModifying()) {
            objectId = data.getObjId();
            model.put("ID", objectId);
            HashMap row = adColumnMapper.selectByid(objectId);
            log.debug(row.toString());

            Function<String, String> getString = name -> model.containsKey(name) ? model.getString(name) : (String) row.get(name);
            Function<String, Long> getLong = name -> model.containsKey(name) ? model.getLong(name) : TypeUtils.castToLong(row.get(name));


            //获取参数
            coltype = getString.apply("COLTYPE");
            dbname = getString.apply("DBNAME");
            desc = getString.apply("DESCRIPTION");
            displaytype = getString.apply("DISPLAYTYPE");
            interpreter = getString.apply("INTERPRETER");
            summethod = getString.apply("SUMMETHOD");
            SEQUENCENAME = getString.apply("SEQUENCENAME");
            v_mask = getString.apply("MASK");
            isak = getString.apply("ISAK");
            isdk = getString.apply("ISDK");
            v_MODIFIABLE = getString.apply("MODIFIABLE");
            v_null = getString.apply("NULLABLE");
            v_obtainmanner = getString.apply("OBTAINMANNER");
            v_fkdisplay = getString.apply("FKDISPLAY");

            AD_LIMITVALUE_GROUP_ID = getLong.apply("AD_LIMITVALUE_GROUP_ID");
            REF_COLUMN_ID = getLong.apply("REF_COLUMN_ID");
            ORDERNO = getLong.apply("ORDERNO");


            data.setUpdateDefaultValue(model);
            HashMap tabrow = adColumnMapper.selectidBytable(objectId);
            tabname = (String) tabrow.get("NAME");
            tableid = ((Long) tabrow.get("ID")).intValue();


            if (model.containsKey("DBNAME") && adColumnMapper.existsWithoutColId(tableid, objectId, dbname)) {
                return data.error(-1, "字段名", "已经存在");
            }
        } else {
            throw data.notSupported();
        }

        if (tabname == null) {
            return data.error(-1, "表", "不存在");
        }

        log.debug("column model ->" + model);


        if (coltype.equals("DATE")) {
            throw data.exception("请使用NUMBER(8)代替 DATE字段类型:", dbname);
        }
        if (dbname.equals("DATE") || dbname.equals("OPERATORID")) {
            throw data.exception("保留字段名称，禁止使用:", dbname);
        }
        if (dbname.indexOf("${TABLE}") > 0) {
            dbname = dbname.replace("${TABLE}", tabname);
        }
        if (desc.indexOf(",") > 0) {
            throw data.exception("字段描述中不能包含逗号", dbname);
        }

        data.checkType(coltype);

        log.debug("v_MODIFIABLE ->" + v_MODIFIABLE);
        // String v_modifiable = null;
        if (displaytype.equals("hr")) {
            v_null = "Y";
            v_MODIFIABLE = "N";
            v_obtainmanner = "trigger";
        } else if (displaytype.equals("button")) {
            if (interpreter == null) {
                throw data.exception("对于button 类型，必须设置字段翻译器!");
            }
            v_null = "Y";
            v_MODIFIABLE = "N";
            v_obtainmanner = "trigger";
        }

        String v_nullsql = null;
        if (v_null.endsWith("N")) {
            v_nullsql = "NOT NULL";
        } else {
            v_nullsql = "NULL";
        }

        //字段关联性检查
        if (coltype.toUpperCase().indexOf("NUMBER") < 0 || (summethod != null && summethod.equals("0"))) {
            summethod = null;
        }

        int v_cnt = 0;

        if (SEQUENCENAME != null) {
            v_cnt = v_cnt + 1;
        }
        if (AD_LIMITVALUE_GROUP_ID != null) {
            v_cnt = v_cnt + 1;
        }
        if (REF_COLUMN_ID != null) {
            v_cnt = v_cnt + 1;
        }
        if (v_cnt > 1) {
            throw data.exception("不允许同时设置编号生成器或下拉选项组或外键(FK)!");
        }


        if (SEQUENCENAME != null) {
            v_obtainmanner = "sheetNo";
            displaytype = "text";
        }

        if ((v_obtainmanner.equals("select") || v_obtainmanner.equals("check")) && AD_LIMITVALUE_GROUP_ID == null) {
            throw data.exception("必须设置对应的下拉选项组！");
        }

        if (v_obtainmanner.equals("object") && REF_COLUMN_ID == null) {
            throw data.exception("必须设置对应的外键(FK)！");
        }

        if (v_obtainmanner.equals("sheetNo") && SEQUENCENAME == null) {
            throw data.exception("必须设置对应的编号生成器！");
        }

        // 只有类型是drp或pop时才做字段类型验证, from:李清轶 by:zzj time:2017.12.05
        if ("drp".equalsIgnoreCase(v_fkdisplay) || "pop".equalsIgnoreCase(v_fkdisplay)) {
            if (v_obtainmanner.equals("object") && !coltype.toLowerCase().equals("number(20)")) {
                throw data.exception("FK 必须是number(20)型!");
            }
        }

        if (v_mask.equals("0000000000")) {
            v_MODIFIABLE = "N";
            v_null = "Y";
        }

        if (v_mask.length() != 10) {
            throw data.exception("Mask must has 10 bits,input is " + v_mask + "(" + dbname + ")");
        }
        if (!v_mask.matches("[01]+")) {
            throw data.exception("Mask contains chars not in (0,1):" + v_mask + "(" + dbname + ")");
        }
        // 第4位(修改权限)是 0, 则第7位(批量修改)也需要是0
        if (v_mask.charAt(3) == '0' && v_mask.charAt(6) != '0') {
            v_mask = v_mask.substring(0, 6) + "0" + v_mask.substring(7);
            model.put("MASK", v_mask);
        }

        //FC-810
        //字段的保存逻辑，若读写规则第2位和第4位为1并且【允许界面修改】=N，则直接将【允许界面修改】更新为Y
        if (!displaytype.equals("hr") && !displaytype.equals("button")) {
            if (v_mask.substring(3, 4).equals("0")) {
                v_MODIFIABLE = "N";
            } else {
                v_MODIFIABLE = "Y";
            }
        }


        //重新设置参数
        {
            model.put("COLTYPE", coltype);
            model.put("DBNAME", dbname);
            model.put("DESCRIPTION", desc);
            model.put("DISPLAYTYPE", displaytype);
            model.put("INTERPRETER", interpreter);
            model.put("SUMMETHOD", summethod);
            model.put("SEQUENCENAME", SEQUENCENAME);
            model.put("MASK", v_mask);
            model.put("ISAK", isak);
            model.put("ISDK", isdk);
            model.put("MODIFIABLE", v_MODIFIABLE);
            model.put("NULLABLE", v_null);
            model.put("OBTAINMANNER", v_obtainmanner);
            model.put("FKDISPLAY", v_fkdisplay);
            model.put("AD_LIMITVALUE_GROUP_ID", AD_LIMITVALUE_GROUP_ID);
            model.put("REF_COLUMN_ID", REF_COLUMN_ID);
            model.put("ORDERNO", ORDERNO);
        }

        if (data.isInserting()) {
            mapperShortcut.insert(model, "AD_COLUMN");
        } else if (data.isModifying()) {
            mapperShortcut.update(model, "AD_COLUMN");
        }

        adColumnMapper.updateName(objectId, tabname.toUpperCase() + "." + dbname.toUpperCase(), dbname.toUpperCase(), v_null, v_MODIFIABLE);

        //ak 判断
        if (isak != null && isak.equals("Y")) {
            adColumnMapper.updateAK(tableid, objectId);
            adTableMapper.updateAK(tableid, objectId);
        } else {
            adTableMapper.updateAK2PK(tableid);
        }
        //dk 判断
        if (isdk != null && isdk.equals("Y")) {
            adColumnMapper.updateDK(tableid, objectId);
            adTableMapper.updateDK(tableid, objectId);
        } else {
            adTableMapper.updateDK2PK(tableid);
        }


        //序号排列
        if (ORDERNO == null) {
            int orderno = adColumnMapper.getMaxOrderNo(tableid);
            adColumnMapper.updateOrderNo(objectId, orderno);
        }

        //-- 修改table.modifieddate
        adTableMapper.updateModifieddate(new Timestamp(System.currentTimeMillis()), tableid);

        //ref_table_id
        adColumnMapper.updateRefTable(objectId);

        if (!data.checkVirtual(dbname)) {
            int pcount = adTableMapper.columnCount(tabname, dbname);

            if (coltype.equalsIgnoreCase("DATETIME")) {
                coltype = "DATE";
            }

            if (coltype.equalsIgnoreCase("DATENUMBER")) {
                coltype = "NUMBER(8)";
            }

            // 判断生成ddl语句 support covert mysql type

            if (pcount == 0) {
                adTableSqlMapper.DDLLog(tableid, "alter table " + tabname + " add " + dbname + " " + data.convertmysqltype(coltype) + v_nullsql);
            } else {
                adTableSqlMapper.DDLLog(tableid, "alter table " + tabname + " modify " + dbname + " " + data.convertmysqltype(coltype) + v_nullsql);
            }

        }

        log.debug(data.success().toJSONObject().toJSONString());

        return data.isInserting() ? data.success(objectId, "AD_COLUMN") : data.success();
    }
}

